//! 政策知识:
//! 从2025年开始到2039年，用15年的时间，将法定退休年龄调整到男职工63周岁，女职工58周岁或55周岁，这是一个渐进的过程。
//!
//! 从2025年1月1日起，男职工和原法定退休年龄为55周岁的女职工，每4个月延1个月。原法定退休年龄为50周岁的女职工，每2个月延1个月。
//! 以男职工为例，明年1月至4月满60周岁的，退休年龄为60周岁零1个月；明年5月至8月满60周岁的，退休年龄为60周岁零2个月，依此类推。
//!
//! 男性延迟法定退休年龄对照表中，显示的出生时间为1965年1月至1976年12月，其中1965年1月至4月出生的男性，退休时间为60周岁零1个月，
//! 延迟1个月。每4个月延迟1月，截止至1976年12月出生的男性，其退休时间为63周岁，延迟36个月。
//!
//! 原法定退休年龄55周岁的女职工也遵循每4个月延1月的延迟退休政策。其对照表中显示的出生时间为1970年1月至1981年12月，
//! 其中1981年12月出生的女性在2039年12月退休，退休年龄为58周岁，延迟退休月数为36个月。
//!
//! 而原法定退休年龄50周岁的女职工遵循每2个月延1月的延迟退休政策。1975年1月至1984年12月出生的普通女工人均在该延迟退休年龄对照表中。
//! 其中，1975年1月至1975年2月出生的女性，改革后的法定退休年龄为50岁1个月，而1975年3月至1975年4月出生的女性，
//! 法定退休年龄为50岁2个月，以此类推至1984年12月出生的女性，在2039年12月退休，其法定退休年龄为55周岁，延迟月数达60个月。
//!

use std::{num::ParseIntError, ops::RangeInclusive};

pub fn retire_time(time: &str, tp: &str) -> String {
    let birth = time_to_birth(time).expect("time有错误");
    if tp == "原法定退休年龄55周岁女职工" {
        FEMAL55.retire_info(birth)
    } else if tp == "原法定退休年龄50周岁女职工" {
        FEMAL50.retire_info(birth)
    } else if tp == "男职工" {
        MALE.retire_info(birth)
    } else {
        "未定义的类别".to_owned()
    }
}

fn time_to_birth(time: &str) -> Result<Birth, String> {
    let mut iter = time.trim().split("-");
    let mut birth = [0; 2];
    for i in 0..2 {
        birth[i] = iter
            .next()
            .map(|s| s.parse::<u32>())
            .map(|x| x.map_err(|e| e.to_string()))
            .unwrap_or_else(|| Err(String::from("输入出生有错误")))?;
    }
    birth.try_into()
}

// 关于定制，比如国家在2030年后，统一制定男性的退休为65.那么定制全局变量：
//const MALE65: RetirePolicy = RetirePolicy::new(65, [(u32::MAX, 1), (1949, 1)], 4, 0); // 把范围的最大点设置为(1949，1)最小值，那么默认都大于这个
// 最大值，采用固定延长，这里设置了0，就代表65岁退休.下面的代码几乎不需要修改。
const FEMAL55: RetirePolicy = RetirePolicy::new(55, [(1970, 1), (1981, 12)], 4, 36);
const FEMAL50: RetirePolicy = RetirePolicy::new(50, [(1975, 1), (1984, 12)], 2, 60);
const MALE: RetirePolicy = RetirePolicy::new(60, [(1965, 1), (1976, 12)], 4, 36);

#[derive(Debug, Clone)]
struct RetirePolicy {
    retired_age: u32,                   // 法定退休年龄(年数)
    birth_range: RangeInclusive<Birth>, // 出生范围
    extend_month: u32,                  // 延长策略(月数)几个月延长1个月
    out_range_extend_month: u32,        // 超出出生范围后，固定的延长月数。
}

impl RetirePolicy {
    #[inline(always)]
    const fn new(
        retired_age: u32,
        birth_range: [(u32, u32); 2],
        extend_month: u32,
        out_range_extend_month: u32,
    ) -> Self {
        let birth_range = Birth::new_unchecked(birth_range[0].0, birth_range[0].1)
            ..=Birth::new_unchecked(birth_range[1].0, birth_range[1].1);
        Self {
            retired_age,
            birth_range,
            extend_month,
            out_range_extend_month,
        }
    }

    fn retire_info(&self, birth: Birth) -> String {
        let extend_month: u32 = if birth < *self.birth_range.start() {
            // 小于最小值范围,没有延长。
            0
        } else if birth > *self.birth_range.end() {
            // 大于最大范围，固定的延长。
            self.out_range_extend_month
        } else {
            // 中间的按照策略计算延长月数
            let ms = birth - *self.birth_range.start();
            ms / 4 + if ms % 4 != 0 { 1 } else { 0 }
        };

        let retire = (birth + self.retired_age * 12) + extend_month;
        let retire_years = self.retired_age as f32 + extend_month as f32 / 12.;
        if extend_month % 12 == 0 {
            format!(
                "{}-{:02},{},{}",
                retire.year(),
                retire.month(),
                self.retired_age + extend_month / 12,
                extend_month
            )
        } else {
            format!(
                "{}-{:02},{:.2},{}",
                retire.year(),
                retire.month(),
                retire_years,
                extend_month
            )
        }
    }
}

//  ------------------------------------------------------------------------------------------------
// 出生年月结构体
#[derive(Debug, Clone, Copy, Eq, Ord)]
struct Birth {
    year: u32,
    month: u32,
}

impl Birth {
    const MIN: Self = Self {
        year: 1949,
        month: 10,
    }; // 最小的出生日期

    #[inline(always)]
    const fn new_unchecked(year: u32, month: u32) -> Self {
        Self { year, month }
    }

    #[inline(always)]
    fn new(year: u32, month: u32) -> Result<Self, String> {
        Birth::try_from([year, month])
    }

    #[inline(always)]
    fn year(&self) -> u32 {
        self.year
    }

    #[inline(always)]
    fn month(&self) -> u32 {
        self.month
    }
}

impl TryFrom<[u32; 2]> for Birth {
    type Error = String;

    // [year,month]
    #[inline(always)]
    fn try_from(value: [u32; 2]) -> Result<Self, Self::Error> {
        if value[0] < 1949 || value[1] > 12 || value[1] < 1 {
            return Err(String::from("年份或者月份输入有错误"));
        }
        Ok(Self {
            year: value[0],
            month: value[1],
        })
    }
}

impl PartialEq for Birth {
    #[inline(always)]
    fn eq(&self, other: &Self) -> bool {
        self.year == other.year && self.month == other.month
    }
}

impl PartialOrd for Birth {
    #[inline(always)]
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        match self.year.partial_cmp(&other.year) {
            Some(core::cmp::Ordering::Equal) => {}
            ord => return ord,
        }
        self.month.partial_cmp(&other.month)
    }
}

// Birth - Birth = 月数
impl std::ops::Sub for Birth {
    type Output = u32;

    #[inline(always)]
    fn sub(mut self, other: Self) -> Self::Output {
        debug_assert!(self >= other);
        if self.month < other.month {
            self.year -= 1;
            self.month += 12;
        }

        // 这里的减法主要针对的是other的月份是1,并不是真正的计算两者之间间隔的月数.
        (self.year - other.year) * 12 + self.month - other.month + 1
    }
}

// Birth + 月数
impl std::ops::Add<u32> for Birth {
    type Output = Self;

    #[inline(always)]
    fn add(mut self, month: u32) -> Self::Output {
        self.month += month;
        if self.month > 12 {
            self.year += self.month / 12;
            if self.month % 12 == 0 {
                self.year -= 1;
                self.month = 12;
            } else {
                self.month = self.month % 12;
            }
        }
        self
    }
}

// Birth += 月数
impl std::ops::AddAssign<u32> for Birth {
    #[inline(always)]
    fn add_assign(&mut self, month: u32) {
        self.month += month;
        if self.month > 12 {
            self.year += self.month / 12;
            if self.month % 12 == 0 {
                self.year -= 1;
                self.month = 12;
            } else {
                self.month = self.month % 12;
            }
        }
    }
}

// Birth - 月数
impl std::ops::Sub<u32> for Birth {
    type Output = Self;

    #[inline(always)]
    fn sub(mut self, month: u32) -> Self::Output {
        if self.month <= month {
            self.year -= 1;
            self.month += 12;
        }
        self.month -= month;
        self
    }
}

// Birth -=月数
impl std::ops::SubAssign<u32> for Birth {
    #[inline(always)]
    fn sub_assign(&mut self, month: u32) {
        if self.month <= month {
            self.year -= 1;
            self.month += 12;
        }
        self.month -= month;
    }
}

//  ------------------------------------------------------------------------------------------------
